/*
#
#  Copyright 2011 Matthew Jannace
#
#  This file is part of RoboCode BlackHoleAgent
#
#  RoboCode BlackHoleAgent is free software: you can redistribute it and/or
#  modify it under the terms of the GNU General Public License as
#  published by the Free Software Foundation, either version 3 of the
#  License, or (at your option) any later version.
#
#  RoboCode BlackHoleAgent is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
#  General Public License for more details.
#
#  You should have received a copy of the GNU General Public License
#  along with RoboCode BlackHoleAgent. If not, see
#  <http://www.gnu.org/licenses/>.
#
 */
package com.jannaceltd.TeamBlackHoleBeer.Modules.Targeting.TargetingMethods;

import com.jannaceltd.TeamBlackHoleBeer.BlackHole_Abstract;
import com.jannaceltd.TeamBlackHoleBeer.Modules.Targeting.Targeting;
import com.jannaceltd.TeamBlackHoleBeer.Utilities.MathUtils;
import robocode.Rules;
import robocode.util.Utils;

/**
 * Class that Performs Exact Linear Targeting
 * @author Matthew Jannace <mjannace@gmail.com>
 * @version 1.0
 *
 * Based on the Linear Targeting Tutorial
 * @link http://robowiki.net/wiki/Linear_Targeting
 */
public class ExactLinearTargeting {

    private BlackHole_Abstract Agent = null;
    private Targeting gun = null;
    //
    private double firePower = 2;
    private double ROBOT_WIDTH = 65;
    private double ROBOT_HEIGHT = 65;
    private double eAbsBearing, rX, rY, bV, eX, eY, eV, eHd;
    private double A, B, C, D, a, b, c, d;
    private double discrim;
    private double t1, t2, t;
    /**
     * Target Interception with bullet
     */
    public double endX, endY;

    /**
     * Creates a new ExactLinearTargeting object
     * @param Agent
     * @param gun
     */
    public ExactLinearTargeting(BlackHole_Abstract Agent, Targeting gun) {
        this.Agent = Agent;
        this.gun = gun;
    }

    /**
     * Perform Predictive Linear Targeting
     */
    public void doExactLinearTargeting() {

        if (Agent.getEnergy() < 15) {
            firePower = Math.min(Math.min(Agent.getEnergy() / 6d, 1300d / Agent.getPos().distance(Agent.target.getPos())), Agent.target.getEnergy() / 3d);
        } else {
            firePower = 2;
        }

        // Variables prefixed with e- refer to enemy, b- refer to bullet and r- refer to robot
        eAbsBearing = Agent.getHeadingRadians() + Agent.target.getBearingRadians();
        rX = Agent.getX();
        rY = Agent.getY();
        bV = Rules.getBulletSpeed(firePower);
        eX = rX + Agent.target.getDistance() * Math.sin(eAbsBearing);
        eY = rY + Agent.target.getDistance() * Math.cos(eAbsBearing);
        eV = Agent.target.getVelocity();
        eHd = Agent.target.getHeadingRadians();

        // These constants make calculating the quadratic coefficients below easier
        A = (eX - rX) / bV;
        B = eV / bV * Math.sin(eHd);
        C = (eY - rY) / bV;
        D = eV / bV * Math.cos(eHd);

        // Quadratic coefficients: a*(1/t)^2 + b*(1/t) + c = 0
        a = A * A + C * C;
        b = 2 * (A * B + C * D);
        c = (B * B + D * D - 1);
        discrim = b * b - 4 * a * c;
        if (discrim >= 0) {

            // Reciprocal of quadratic formula
            t1 = 2 * a / (-b - Math.sqrt(discrim));
            t2 = 2 * a / (-b + Math.sqrt(discrim));
            t = Math.min(t1, t2) >= 0 ? Math.min(t1, t2) : Math.max(t1, t2);

            // Assume enemy stops at walls
            endX = MathUtils.Limit(eX + eV * t * Math.sin(eHd), ROBOT_WIDTH / 2, Agent.getBattleFieldWidth() - ROBOT_WIDTH / 2);
            endY = MathUtils.Limit(eY + eV * t * Math.cos(eHd), ROBOT_HEIGHT / 2, Agent.getBattleFieldHeight() - ROBOT_HEIGHT / 2);
            Agent.setTurnGunRightRadians(
                    Utils.normalRelativeAngle(
                    Math.atan2(endX - rX, endY - rY) - Agent.getGunHeadingRadians()));

            gun.dofire(firePower);
        }
    }
}
